package com.zs.juc.thread;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * FutureTask在高并发环境下确保任务只执行一次
 *
 * @author madison
 * @description
 * @date 2021/6/1 17:27
 */
public class FutureTest2 {
    //们通过加锁确保高并发环境下的线程安全，也确保了connection只创建一次，然而确牺牲了性能。
    // 改用ConcurrentHash的情况下，几乎可以避免加锁的操作，性能大大提高，但是在高并发的情况下有可能出现Connection被创建多次的现象
    private Map<String, Connection> connectionPool = new HashMap<String, Connection>();
    //这时最需要解决的问题就是当key不存在时，创建Connection的动作能放在connectionPool之后执行，这正是FutureTask发挥作用的时机
    private ConcurrentHashMap<String, FutureTask<Connection>> connectionPool1 = new ConcurrentHashMap<>();
    private ReentrantLock lock = new ReentrantLock();

    public Connection getConnection(String key) {
        try {
            lock.lock();
            if (connectionPool.containsKey(key)) {
                return connectionPool.get(key);
            } else {
                //创建 Connection
                Connection connection = createConnection();
                connectionPool.put(key, connection);
                return connection;
            }
        } finally {
            lock.unlock();
        }
    }

    public Connection getConnection1(String key) throws ExecutionException, InterruptedException {
        FutureTask<Connection> connectionFutureTask = connectionPool1.get(key);
        if (connectionFutureTask != null) {
            return connectionFutureTask.get();
        } else {
            Callable<Connection> callable = () -> createConnection();
            FutureTask<Connection> newTask = new FutureTask<>(callable);
            connectionFutureTask = connectionPool1.putIfAbsent(key, newTask);
            if (connectionFutureTask == null) {
                connectionFutureTask = newTask;
                connectionFutureTask.run();
            }
            return connectionFutureTask.get();
        }
    }

    //创建Connection（根据业务需求，自定义Connection）
    private Connection createConnection() {
        return null;
    }

    public static void main(String[] args) {

    }
}
